package com.wef.system.service.impl;

import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Random;
import java.util.Set;

import org.apache.struts.Globals;
import org.hibernate.Hibernate;

import com.gfa4j.acl.AclEntry;
import com.gfa4j.query.Field;
import com.gfa4j.query.Page;
import com.gfa4j.query.QueryInfo;
import com.gfa4j.service.impl.BaseServiceImpl;
import com.gfa4j.util.CommonUtils;
import com.gfa4j.util.StringUtils;
import com.gfa4j.web.SessionManager;
import com.gfa4j.web.UserDetail;
import com.gfa4j.wef.taglib.Constants;
import com.wef.common.service.SessionConstants;
import com.wef.common.service.UserInfo;
import com.wef.system.entity.AclCondition;
import com.wef.system.entity.AclPermission;
import com.wef.system.entity.MenuGroup;
import com.wef.system.entity.MenuGroupTitle;
import com.wef.system.entity.MenuItem;
import com.wef.system.entity.MenuItemTitle;
import com.wef.system.entity.Module;
import com.wef.system.entity.ModuleTitle;
import com.wef.system.entity.RoleMenuButton;
import com.wef.system.entity.RoleMenuItem;
import com.wef.system.entity.User;
import com.wef.system.entity.ViewButton;
import com.wef.system.entity.domain.UserDomain;
import com.wef.system.service.LoginService;

public class LoginServiceImpl extends BaseServiceImpl implements LoginService {
	private List<String> aclExcludeEntityNames = new ArrayList<String>();

	@SuppressWarnings("unchecked")
	public UserDetail login(String userCode, String password) {
		if (StringUtils.isEmpty(userCode) || StringUtils.isEmpty(password))
			return null;
		// throw new BusinessRuntimeException(getMessage("errors.login"));

		QueryInfo queryInfo = new QueryInfo(User.class);
		List<Field> fields = new ArrayList<Field>();

		Field userCodeField = new Field(UserDomain.userCode);
		userCodeField.setFieldValue(userCode);
		userCodeField.setCondition(Field.CONDITION_EQ);

		Field passwordField = new Field(UserDomain.password);
		passwordField.setFieldValue(encryptPassword(password));
		passwordField.setCondition(Field.CONDITION_EQ);

		fields.add(userCodeField);
		fields.add(passwordField);

		queryInfo.setFields(fields);
		List users = ((Page) super.findByQuery(queryInfo)).getList();

		if (users == null || users.size() == 0) {
			// throw new BusinessRuntimeException(getMessage("errors.login"));
			return null;
		}

		User user = (User) users.get(0);

		if (user.getDefaultLang() == null)
			user.setDefaultLang("zh_CN");
		// LogUvService logUvService = (LogUvService) SpringContextUtils
		// .getInstance().getBean("logUvService");
		// QueryInfo queryInfo1 = new QueryInfo(LogUv.class);
		// List<Field> uvFields = new ArrayList<Field>();
		//
		// Field uvNameField = new Field("uvName");
		// uvNameField.setFieldValue(userCode);
		// uvNameField.setCondition(Field.CONDITION_GE);
		//
		// Field uvDateField = new Field("uvDate");
		// SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		// String datetime = sdf.format(new Date());
		// try {
		// uvDateField.setFieldValue(sdf.parse(datetime.toString()));
		// } catch (ParseException e) {
		// // TODO Auto-generated catch block
		// e.printStackTrace();
		// }
		// uvDateField.setCondition(Field.CONDITION_GE);
		//
		// uvFields.add(uvNameField);
		// uvFields.add(uvDateField);
		//
		// queryInfo1.setFields(uvFields);
		// List uvList = ((Page) super.findByQuery(queryInfo1)).getList();
		// if (uvList.size()==0) {
		// LogUv logUv = new LogUv();
		// logUv.setUvName(userCode);
		// // logUv.setUvIp(ip);
		// logUv.setUvDate(new Date());
		// logUvService.addLogUv(logUv);
		// }
		UserInfo userInfo = new UserInfo();
		userInfo.setUserCode(userCode);
		userInfo.setOfficeCode(user.getOfficeCode());
		userInfo.setObject(user);

		/*
		 * 自定义资源权限 Map aclMap = new HashMap(); // company_code= 当前用户所属公司 aclMap.put(UserInfo.COMPANY_CODE, user.getCompanyCode()); aclMap.put("createdByUser", "liuj");
		 * 
		 * // company_code= 当前用户所属公司 or '58000000000' or '14180000000'... List aclList = new ArrayList(); aclList.add(user.getCompanyCode()); aclList.add("58000000000"); aclList.add("14180000000"); aclMap.put(UserInfo.ACl_LIST, aclList);
		 * 
		 * userInfo.setAclMap(aclMap);
		 */

		List menuItems = loadMenuItem(userCode);
		userInfo.setMenuItems(menuItems);
		userInfo.setViewButtons(loadViewButton(userCode));

		// Acl Permissions
		List aclPermissions = findAclPermissionByUserID(user.getUserId());
		AclEntry aclEntry = convertAclPermissionsByEntityName(aclPermissions);
		aclEntry.setUserID(user.getUserId());
		userInfo.setAclEntry(aclEntry);

		String[] language = user.getDefaultLang().split("_");

		if (language.length > 1)
			userInfo.setDefaultLang(new Locale(language[0], language[1]));
		else
			userInfo.setDefaultLang(new Locale(language[0], ""));

		userInfo.setPrincipalGroupCode("00000000000");
		userInfo.setCompanyCode(user.getCompanyCode());
		userInfo.setUserModules(initUserModules(menuItems));
		Map<String, List<String>> mapView2Button = this.loadMIVBNameMap(userInfo);
		userInfo.setUserViewToButtonMap(mapView2Button);

		SessionManager.setUserDetail(userInfo);
		// SessionManager.setAttribute(SessionConstants.COMPANY_CODE,
		// user.getCompanyCode());
		SessionManager.setAttribute(SessionConstants.LANGUAGE, user.getDefaultLang());

		// jQueryUI Themes主题库
		// black-tie,blitzer,cupertino,dark-hive,dot-luv,eggplant,excite-bike,flick
		// hot-sneaks,humanity,le-frog,mint-choc,overcast,pepper-grinder,redmond,smoothness
		// south-street,start,sunny,swanky-purse,trontastic,ui-darkness,ui-lightness,vader
		
		String[] themes = {"blitzer","humanity","mint-choc","redmond","smoothness","start","sunny","ui-lightness"};
		SessionManager.setAttribute(SessionConstants.THEMES, themes[new Random().nextInt(themes.length)]);
		SessionManager.setAttribute(Constants.SESSION_USER_MENUITEM_VIEWBUTTON_MAP, mapView2Button);

		return new UserInfo();
	}

	public UserDetail getUserDetail() {
		return SessionManager.getUserDetail();
	}

	public boolean logOut() {
		SessionManager.logout();
		// SessionManager.setSession(null);
		return true;
	}

	@SuppressWarnings("unchecked")
	private List loadMenuItem(String userCode) {
		StringBuilder hql = new StringBuilder();
		hql.append(" select distinct roleMenuItem.menuItem from ");
		hql.append(RoleMenuItem.class.getName());
		hql.append(" as roleMenuItem");
		hql.append(" left join roleMenuItem.role as role");
		hql.append(" left join role.roleUsers as roleUsers");
		hql.append(" left join roleUsers.user user");
		hql.append(" where ");
		hql.append(" user.userCode = :userCode");
		hql.append(" order by roleMenuItem.menuItem.menuGroup.menuGrpSeq,roleMenuItem.menuItem.menuItemSeq");

		Map<String, Object> queryParam = new HashMap<String, Object>();
		queryParam.put("userCode", userCode);

		List result = findByNamedParam(hql.toString(), queryParam);
		for (Object obj : result) {
			MenuItem menuItem = (MenuItem) obj;
			Hibernate.initialize(menuItem.getMenuItemTitles());
		}
		return result;
	}

	@SuppressWarnings("unchecked")
	private List loadViewButton(String userCode) {

		StringBuilder hql = new StringBuilder();
		hql.append(" select distinct roleMenuButton.viewButton from ");
		hql.append(RoleMenuButton.class.getName());
		hql.append(" as roleMenuButton");
		hql.append(" left join roleMenuButton.roleMenuItem as roleMenuItem");
		hql.append(" left join roleMenuItem.role as role");
		hql.append(" left join role.roleUsers as roleUsers");
		hql.append(" left join roleUsers.user as user ");
		hql.append(" where ");
		hql.append(" user.userCode = :userCode");

		Map<String, Object> queryParam = new HashMap<String, Object>();
		queryParam.put("userCode", userCode);

		return findByNamedParam(hql.toString(), queryParam);
	}

	@SuppressWarnings("unchecked")
	private Map<String, List<String>> loadMIVBNameMap(UserDetail userDetail) {
		Map<String, List<String>> mapMiVbName = new HashMap<String, List<String>>();

		for (ViewButton viewButton : (List<ViewButton>) userDetail.getViewButtons()) {
			String miName = viewButton.getMenuItem().getViewId();
			List<String> lstVbNams = mapMiVbName.get(miName);
			if (lstVbNams == null) {
				lstVbNams = new ArrayList<String>();
				mapMiVbName.put(miName, lstVbNams);
			}
			lstVbNams.add(viewButton.getBtnName());
		}

		return mapMiVbName;
	}

	/**
	 * Encrypt password
	 * 
	 * @param password
	 * @return
	 */
	public static String encryptPassword(String password) {
		try {
			MessageDigest md = MessageDigest.getInstance("MD5");

			byte[] digestResult = md.digest(StringUtils.defaultString(password).getBytes());

			StringBuffer hexValue = new StringBuffer();

			for (int i = 0; i < digestResult.length; i++) {
				int val = ((int) digestResult[i]) & 0xff;
				hexValue.append(StringUtils.leftPad(Integer.toHexString(val), 2, '0'));
			}
			return hexValue.toString();
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		return password;
	}

	/**
	 * return Module-MenuGroup-MenuItem tree from menuItems, added by guoxl 2009-05-01
	 * 
	 * @param menuItems
	 * @return modified by shixy 2009-05-27 只有当ShowInConsole为true时才在界面左侧导航栏显示 If ShowInConsole is true,show in left console.....
	 */
	public Map<String, Module> initUserModules(List<MenuItem> menuItems) {
		Set<Module> setMD = new HashSet<Module>();
		Set<MenuGroup> setMG = new HashSet<MenuGroup>();
		Set<MenuItem> setMI = new HashSet<MenuItem>();

		for (MenuItem mi : menuItems) {
			// modified by shixy 2009-05-27
			if (mi.getShowInConsole() != null && mi.getShowInConsole()) {
				Module module = mi.getMenuGroup().getModule();
				Hibernate.initialize(module.getModuleTitles());
				setMD.add(module);

				MenuGroup menuGroup = mi.getMenuGroup();
				Hibernate.initialize(menuGroup.getMenuGroupTitles());
				setMG.add(mi.getMenuGroup());

				setMI.add(mi);
			}
		}

		Map<String, Module> lstMD = new HashMap<String, Module>();
		for (Module md : setMD) {
			Set<MenuGroup> setMGResult = new HashSet<MenuGroup>();
			for (MenuGroup mg : setMG) {
				Set<MenuItem> setMIResult = new HashSet<MenuItem>();
				for (MenuItem mi : setMI) {
					if (mi.getMenuGroup().equals(mg)) {
						setMIResult.add(mi);
					}
				}
				mg.setMenuItems(setMIResult);
				super.getHibernateSession().evict(mg);// add by xiaojy
				if (mg.getModule().equals(md)) {
					setMGResult.add(mg);
				}
			}
			md.setMenuGroups(setMGResult);
			super.getHibernateSession().evict(md);// addy by xiaojy
			lstMD.put(md.getModuleCode(), md);
		}

		return lstMD;
	}

	private List loadViewButtonUrl(UserDetail userDetail) {
		List buttonUrls = new ArrayList();
		for (ViewButton viewButton : (List<ViewButton>) userDetail.getViewButtons()) {
			buttonUrls.add(viewButton.getButtonUrl());
		}
		return buttonUrls;
	}

	public boolean changeModule(String moduleCode) {
		// SessionManager.setAttribute(SessionConstants.CURRENT_MODULE_CODE,
		// moduleCode);
		UserInfo.getInstance().setCurrentModuleCode(moduleCode);
		return true;
	}

	public boolean setSubModelStatus(String value) {
		SessionManager.setAttribute(SessionConstants.SUBMODEL_STATUS, value);
		return true;
	}

	public String getSubModelStatus() {
		return (String) SessionManager.getAttribute(SessionConstants.SUBMODEL_STATUS);
	}

	public void setLangEn() {
		SessionManager.setAttribute(Globals.LOCALE_KEY, Locale.ENGLISH);
		SessionManager.setAttribute(SessionConstants.LANGUAGE, "en");
		UserDetail userDetail = SessionManager.getUserDetail();
		if (!CommonUtils.isEmpty(userDetail)) {
			userDetail.setDefaultLang(Locale.ENGLISH);
		}
	}

	public void setLangCnT() {
	}

	public void setLangCnS() {
		SessionManager.setAttribute(Globals.LOCALE_KEY, Locale.SIMPLIFIED_CHINESE);
		SessionManager.setAttribute(SessionConstants.LANGUAGE, "zh_CN");
		UserDetail userDetail = SessionManager.getUserDetail();
		if (!CommonUtils.isEmpty(userDetail)) {
			userDetail.setDefaultLang(Locale.SIMPLIFIED_CHINESE);
		}
	}

	private com.gfa4j.acl.entity.AclPermission convertGfaAclPermissions(AclPermission permission) {
		com.gfa4j.acl.entity.AclPermission gfaPermission = new com.gfa4j.acl.entity.AclPermission();
		gfaPermission.setAclPermissionId(permission.getAclPermissionId());
		gfaPermission.setEntityName(permission.getEntityName());
		gfaPermission.setCrudType(permission.getCrudType());
		Set<com.gfa4j.acl.entity.AclCondition> gfaConditionSet = new HashSet<com.gfa4j.acl.entity.AclCondition>();
		for (AclCondition condition : (Set<AclCondition>) permission.getAclConditions()) {
			gfaConditionSet.add(convertGfaAclCodition(condition));
		}
		gfaPermission.setAclConditions(gfaConditionSet);
		return gfaPermission;
	}

	private com.gfa4j.acl.entity.AclCondition convertGfaAclCodition(AclCondition condition) {
		com.gfa4j.acl.entity.AclCondition gfaCondition = new com.gfa4j.acl.entity.AclCondition();
		gfaCondition.setAclConditionId(condition.getAclConditionId());
		gfaCondition.setPropertyName(condition.getPropertyName());
		gfaCondition.setOperator(condition.getOperator());
		gfaCondition.setValue(condition.getValue());
		gfaCondition.setLogicNode(condition.getLogicNode());
		if (!condition.getChildConditions().isEmpty()) {
			Set<com.gfa4j.acl.entity.AclCondition> gfaConditionSet = new HashSet<com.gfa4j.acl.entity.AclCondition>();
			for (AclCondition childCondition : (Set<AclCondition>) condition.getChildConditions()) {
				gfaConditionSet.add(convertGfaAclCodition(childCondition));
			}
			gfaCondition.setChildConditions(gfaConditionSet);
		}
		return gfaCondition;
	}

	@SuppressWarnings("unchecked")
	public List findAclPermissionByUserID(String userID) {
		StringBuilder queryString = new StringBuilder();
		queryString.append("select distinct ap from AclPermission ap ");
		queryString.append("  where ap.role in ");
		queryString.append(" (select roleUser.role from RoleUser roleUser ");
		queryString.append(" left join roleUser.user user ");
		queryString.append(" where user.userId = :userID )");

		return this.findByNamedParam(queryString.toString(), new String[] { "userID" }, new String[] { userID });
	}

	@SuppressWarnings("unchecked")
	private AclEntry convertAclPermissionsByEntityName(List<com.wef.system.entity.AclPermission> aclPermissions) {

		for (Iterator it = aclPermissions.iterator(); it.hasNext();) {
			com.gfa4j.acl.entity.AclPermission gfaPermission = convertGfaAclPermissions((AclPermission) it.next());
			if (aclExcludeEntityNames.contains(gfaPermission.getEntityName()))
				it.remove();
		}

		AclEntry aclEntry = new AclEntry();

		for (AclPermission permission : aclPermissions) {

			com.gfa4j.acl.entity.AclPermission gfaPermission = convertGfaAclPermissions(permission);

			String entityName = gfaPermission.getEntityName().split("\\.")[1];

			Map map = new HashMap();

			if (gfaPermission.getCrudType().equals(com.gfa4j.acl.entity.AclPermission.CRUDTYPE_CREATE)) {
				map = aclEntry.getCreatePermisssions();
			}

			if (gfaPermission.getCrudType().equals(com.gfa4j.acl.entity.AclPermission.CRUDTYPE_DELETE)) {
				map = aclEntry.getDeletePermissions();
			}

			if (gfaPermission.getCrudType().equals(com.gfa4j.acl.entity.AclPermission.CRUDTYPE_UPDATE)) {
				map = aclEntry.getUpdatePermissions();
			}

			if (gfaPermission.getCrudType().equals(com.gfa4j.acl.entity.AclPermission.CRUDTYPE_READ)) {
				map = aclEntry.getQueryPermissions();
			}

			if (map.get(entityName) != null) {
				List permissions = (List) map.get(entityName);
				permissions.add(gfaPermission);
			} else {
				List permissions = new ArrayList();
				permissions.add(gfaPermission);
				map.put(entityName, permissions);
			}
		}

		return aclEntry;
	}

	public void setAclExcludeEntityNames(List<String> aclExcludeEntityNames) {
		this.aclExcludeEntityNames = aclExcludeEntityNames;
	}

	public void changeThemes(String themes) {
		SessionManager.setAttribute(SessionConstants.THEMES, themes);
	}

	public static String getInternationalInfo(Module module) {
		String language = SessionManager.getUserDetail().getDefaultLang().toString();
		String title = module.getModuleTitleKey();
		Iterator it = module.getModuleTitles().iterator();
		while (it.hasNext()) {
			ModuleTitle moduleTitle = (ModuleTitle) it.next();
			if (language.equalsIgnoreCase(moduleTitle.getLang())) {
				title = moduleTitle.getTitle();
				break;
			}
		}
		return title;
	};

	public static String getInternationalInfo(MenuGroup menuGroup) {
		String language = SessionManager.getUserDetail().getDefaultLang().toString();
		String title = menuGroup.getMenuGrpTitleKey();
		Iterator it = menuGroup.getMenuGroupTitles().iterator();
		while (it.hasNext()) {
			MenuGroupTitle menuGroupTitle = (MenuGroupTitle) it.next();
			if (language.equalsIgnoreCase(menuGroupTitle.getLang())) {
				title = menuGroupTitle.getTitle();
				break;
			}
		}
		return title;
	};

	public static String getInternationalInfo(MenuItem mi) {
		String language = SessionManager.getUserDetail().getDefaultLang().toString();
		String title = mi.getMenuItemTitleKey();
		Iterator it = mi.getMenuItemTitles().iterator();
		while (it.hasNext()) {
			MenuItemTitle menuItemTitle = (MenuItemTitle) it.next();
			if (language.equalsIgnoreCase(menuItemTitle.getLang())) {
				title = menuItemTitle.getTitle();
				break;
			}
		}
		return title;
	};
}
